#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import os
import sys
import time
import manpa
import shutil
import jinja2
import subprocess
import mirrors.plugin
from selenium.webdriver.common.by import By


class Main:

    def __init__(self):
        self.dataDir = mirrors.plugin.params["storage-file"]["data-directory"]
        self.mp = manpa.Manpa()
        self.p = InfoPrinter()
        self.url = "https://katagotraining.org/networks"

    def run(self):
        selfDir = os.path.dirname(os.path.realpath(__file__))
        wwwDir = os.path.join(selfDir, "www")

        # get information
        strongestNetwork = None
        strongestNetworkReleaseTime = None
        strongestNetworkEloRating = None
        strongestNetworkLink = None
        self.p.print("Get information from %s:" % (self.url))
        self.p.incIndent()
        try:
            with self.mp.open_selenium_client() as driver:
                driver.get_and_wait(self.url)
                aTag = driver.find_element(by=By.XPATH, value=".//span[text()='Strongest confidently-rated network:']/following-sibling::a")
                strongestNetwork = aTag.text
                self.p.print("strongest network: %s" % (strongestNetwork))
                strongestNetworkLink = aTag.get_attribute("href")
                self.p.print("strongest network link: %s" % (strongestNetworkLink))
                tdList = driver.find_elements(by=By.XPATH, value=".//td[contains(text(),'%s')]/following-sibling::td" % (strongestNetwork))
                strongestNetworkReleaseTime = tdList[0].text.strip()
                self.p.print("strongest network release time: %s" % (strongestNetworkReleaseTime))
                strongestNetworkEloRating = tdList[1].text.strip()
                self.p.print("strongest network elo rating: %s" % (strongestNetworkEloRating))
        finally:
            self.p.decIndent()

        # download strong networks
        self.p.print("Download strong networks:")
        self.p.incIndent()
        try:
            fullDir = os.path.join(self.dataDir, "data", "strong-networks")
            os.makedirs(fullDir, exist_ok=True)
            self._downloadFilesToDirThenClearDir([
                strongestNetworkLink,
                "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170-b40c256x2-s5095420928-d1229425124.bin.gz",         # b40 network for the completed g170 run, elo?
                "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170-b30c320x2-s4824661760-d1229536699.bin.gz",         # b30 network for the completed g170 run, elo?
                "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170e-b20c256x2-s5303129600-d1228401921.bin.gz",        # b20 network for the completed g170 run, elo?
            ], fullDir)
            os.symlink(os.path.basename(strongestNetworkLink), os.path.join(fullDir, "strongest-network.bin.gz"))
        finally:
            self.p.decIndent()

        # download pure networks
        self.p.print("Download pure networks:")
        self.p.incIndent()
        try:
            fullDir = os.path.join(self.dataDir, "data", "pure-networks")
            os.makedirs(fullDir, exist_ok=True)
            self._downloadFilesToDirThenClearDir([
                "https://github.com/lightvector/KataGo/releases/download/v1.4.0/g170-b40c256x2-s3708042240-d967973220.bin.gz",          # g170 b40 pure network, elo?
                "https://github.com/lightvector/KataGo/releases/download/v1.4.0/g170-b30c320x2-s3530176512-d968463914.bin.gz",          # g170 b30 pure network, elo?
                "https://github.com/lightvector/KataGo/releases/download/v1.4.0/g170-b20c256x2-s4384473088-d968438914.bin.gz",          # g170 b20 pure network, elo?
            ], fullDir)
        finally:
            self.p.decIndent()

        # generate www directory
        self.p.print("Generate www directory:")
        if True:
            Util.forceDelete(os.path.join(self.dataDir, "css"))
            shutil.copytree(os.path.join(wwwDir, "css"), os.path.join(self.dataDir, "css"))

            # generate web pages
            tm = jinja2.Environment(loader=jinja2.FileSystemLoader(wwwDir)).get_template("index.html.jinja2")
            with open(os.path.join(self.dataDir, "index.html"), "w") as f:
                f.write(tm.render({
                    "strongest_network": strongestNetwork,
                    "strongest_network_release_time": strongestNetworkReleaseTime,
                    "strongest_network_elo_rating": strongestNetworkEloRating,
                    "strongest_network_link": os.path.join("./data/strongest-networks/%s" % (os.path.basename(strongestNetworkLink))),
                }))

        # finished
        self.p.print("All done.")

    def _downloadFilesToDirThenClearDir(self, urlList, dstDir):
        fnList = os.listdir(dstDir)
        newFnList = [os.path.basename(x) for x in urlList]

        for i in range(0, len(urlList)):
            localFile = os.path.join(dstDir, newFnList[i])
            try:
                fnList.remove(newFnList[i])
                self.p.print("file already downloaded: %s" % (localFile))
                continue
            except ValueError:
                pass

            tmpFullFn = os.path.join(os.path.dirname(localFile), ".downloading")
            while True:
                try:
                    subprocess.check_call(["wget", "--quiet", "--no-check-certificate", "-O", tmpFullFn, urlList[i]])      # always re-dowloand
                    break
                except subprocess.CalledProcessError as e:
                    if e.returncode == 8:       # not found
                        raise
                    self.p.print("download failed and try again: %s" % str(e))
                    time.sleep(60)
            os.rename(tmpFullFn, localFile)
            self.p.print("file downloaded: %s" % (localFile))

        for fn in fnList:
            Util.forceDelete(os.path.join(dstDir, fn))


class InfoPrinter:

    class _InfoPrinterIndenter:

        def __init__(self, parent, message):
            self._parent = parent
            self._parent.print(message)
            self._parent.incIndent()

        def __enter__(self):
            return self

        def __exit__(self, type, value, traceback):
            self._parent.decIndent()

    def __init__(self):
        self.indent = 0

    def incIndent(self):
        self.indent = self.indent + 1

    def decIndent(self):
        assert self.indent > 0
        self.indent = self.indent - 1

    def print(self, s):
        line = ""
        line += "\t" * self.indent
        line += s
        print(line)

    def printAndIndent(self, s):
        return self._InfoPrinterIndenter(self, s)


class Util:

    @staticmethod
    def forceDelete(path):
        if os.path.islink(path):
            os.remove(path)
        elif os.path.isfile(path):
            os.remove(path)
        elif os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.lexists(path):
            os.remove(path)             # other type of file, such as device node
        else:
            pass                        # path does not exist, do nothing


###############################################################################

if __name__ == "__main__":
    with mirrors.plugin.ApiClient() as sock:
        try:
            Main().run()
            sock.progress_changed(100)
        except Exception:
            sock.error_occured(sys.exc_info())
            raise
